package fiarproject;

import java.util.ArrayList;

public class Game {
    private Board board;
    private int winner;

    private ArrayList<WinningRow> blackWins = new ArrayList<WinningRow>();
    private ArrayList<WinningRow> whiteWins = new ArrayList<WinningRow>();

    /***
     * Constructor initiates calculation of wins
     * @param board
     */
    public Game(Board board) {
        this.board = board;
        calculateWinner(FiarGame.BLACK);
        calculateWinner(FiarGame.WHITE);
    }

    /***
     * Returns the number of counted black rows in the current board of this game
     * @return number of winning rows
     */
    public int getBlackWins() {
        return blackWins.size();
    }

    /***
     * Returns the number of counted white rows in the current board of this game
     * @return number of winning rows
     */
    public int getWhiteWins() {
        return whiteWins.size();
    }

    /***
     *  Returns the integer value of the game state
     * @return BLACK, WHITE, DRAW or NONE
     */
    public int getWinner() {
        return winner;
    }


    /***
     * Work method
     * @param pieceType This is run twice for each side
     */
    public void calculateWinner(int pieceType) {
        /***
         * Horizontal and Vertical
         */
        for(int i = 0; i < board.getBoardWidth(); i++) {
            for(int j = 0; j < (board.getBoardWidth()-3); j++) {
                horizontal(j, i, pieceType);
                vertical(i, j, pieceType);
            }
        }

        /***
         * Bottom left to middle
         */
        for(int j = 3; j < board.getBoardWidth(); j++) {
            for(int i = 0; i < j-2; i++) {
                checkRowDiagonal(i, j - i, pieceType, true, false);
            }
        }

        /***
         * Top right to middle
         */
        for(int j = 1; j < board.getBoardWidth()-3; j++) {
            for(int i = 0; i < (board.getBoardWidth()-3)-j ; i++) {
                checkRowDiagonal((board.getBoardWidth() - 1)-i, j + i, pieceType, false, true);
            }
        }

        /***
         * Top left to middle
         */
        for(int i=1; i <board.getBoardWidth()-3; i++) {
            for(int j= 0; j < (board.getBoardWidth()-3)-i; j++) {
                checkRowDiagonal(i + j, j, pieceType, true, true);
            }
        }

        /***
         * Bottom right to middle
         */
         for(int i = 3; i < board.getBoardWidth()-1; i++) {
             for(int j = 0; j < i-2; j++) {
                 checkRowDiagonal(i - j, (board.getBoardWidth()-1)-j, pieceType, false, false);
             }
         }
        setWinner();
    }

    /***
     * Sets the winner value according to completeness of the game and of white and black rows counted
     */
    private void setWinner() {
        if(!board.isBoardFull()) winner = FiarGame.NONE;
        else if(getBlackWins()>getWhiteWins()) winner = FiarGame.BLACK;
        else if(getWhiteWins()>getBlackWins()) winner = FiarGame.WHITE;
        else { winner = FiarGame.DRAW; }
    }

    private void checkRowDiagonal(int i, int j, int pieceType, boolean iPos, boolean jPos) {
        int x = iPos?1:-1;
        int y = jPos?1:-1;

        for(int k=0; k<4; k++) {
           if(!((board.getPosition(i+k*x, j+k*y) == pieceType))) return;
        }
            addRow(new Pair(i, j), new Pair(i + x*1, j + y*1), new Pair(i + x*2, j + y*2), new Pair(i + x*3, j + y*3), pieceType);
    }

    private void vertical(int i, int j, int pieceType) {
        for(int k=0; k < 4; k++) {
            if(!(board.getPosition(i, j+k) == pieceType)) return;
        }
            addRow(new Pair(i,j), new Pair(i, j+1), new Pair(i, j+2), new Pair(i, j+3), pieceType);
    }

    private void horizontal(int i, int j, int pieceType) {
        for(int k=0; k < 4; k++) {
            if(!(board.getPosition(i+k, j) == pieceType)) return;
        }
            addRow(new Pair(j, i), new Pair(j, i+1), new Pair(j, i+2), new Pair(j, i+3), pieceType);
    }

    /***
     * Checks the which player's row is to be added and then adds it to the win array iff it is not already added
     * @param p1
     * @param p2
     * @param p3
     * @param p4
     * @param pieceType
     */
    private void addRow(Pair p1, Pair p2, Pair p3, Pair p4, int pieceType) {
        WinningRow r = new WinningRow(p1, p2, p3, p4);
        if(pieceType == FiarGame.BLACK && !r.isIn(blackWins)) blackWins.add(r);
        else if(pieceType == FiarGame.WHITE && !r.isIn(whiteWins)) whiteWins.add(r);
    }
}
